/***************************************************************************
 *   Copyright (C) 2007 by Marco Bonifazi				   *
 *   marcobonifazi@gmail.com 						   *
 *                                                                         *
 *   Permission is hereby granted, free of charge, to any person obtaining * 
 *   a copy of this software and associated documentation files (the       *
 *   "Software"), to deal in the Software without restriction, including   *
 *   without limitation the rights to use, copy, modify, merge, publish,   *
 *   distribute, sublicense, and/or sell copies of the Software, and to    * 
 *   permit persons to whom the Software is furnished to do so, subject to *
 *   the following conditions:                                             *
 *                                                                         *
 *   The above copyright notice and this permission notice shall be        *
 *   included in all copies or substantial portions of the Software.       *
 *                                                                         *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR     *
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
 *   OTHER DEALINGS IN THE SOFTWARE.                                       *
 ***************************************************************************/
 
#include "grafi.h"

int row_ext, col_ext;
int verify;
config* current_cfg;
grid* current_grid,* start_grid;
int grid_to_display;
int consider_free = 0;
int test;
int opengl; 

void push_area(list_areas** first,  int area ){
	/* Push an area at the beginning of a stack */

	list_areas* list = malloc( sizeof( list_areas) );
	
	if (list != NULL){
		list->next = *first;
		list->area = area;
		*first = list;
	}
	else {
		printf("Memoria non disponibile\n");
	
	}
}

int delete_area_from_list(list_areas** first,  int area ){
	int deleted = 0; /* Not any node deleted */
	list_areas* previous;
	list_areas* current;
	list_areas* temp;
	
	if ( (*first)->area == area ){ /* Deleting node is the first*/
		temp = *first;
		*first = (*first)->next;
		free(temp);
		temp = NULL;
		deleted = 1;
	}
	else {
		previous = *first; 
		current = (*first)->next;
	
		while ( current != NULL && current->area != area){
			previous = current;
			current = current->next;
		}
		if ( current != NULL ){ /* While didn't break for NULL */
			temp = current;
			previous->next = current->next;
			free (temp);
			deleted = 1;
		}
	}
	if (deleted == 1 && test == 1 ) 
		printf("One or more node are deleted from the list\n");
	return deleted;
}

void assign_label_list_arcs( list_real_arcs* real_arcs){
	/*  For each arc it takes the node assigning them the "label" of the arc. 
	 * In this case the "label" is the starting and end arc nodes which represent the limits */

	list_nodes* temp = NULL;
	
	while ( real_arcs != NULL ){
		temp = real_arcs->nodes;
		temp->node->n1 = NULL;	/* First node is real one and it has not double labels*/
		temp->node->n2 = NULL;

		temp = temp->next;

		while ( temp->next != NULL){
			temp->node->n1 = real_arcs->n_start;
			temp->node->n2 = real_arcs->n_end;

			temp = temp->next;
		}

		temp->node->n1 = NULL;	/* Last node is real one and it has not double labels*/
		temp->node->n2 = NULL;	

		real_arcs = real_arcs->next;
	}

	if (test == 1) printf("Print of a real arcs list - End\n");
}

list_real_arcs* create_list_arcs( grid* gr, int level){
	/* Takes a node and visit all his neighbours in a wide visit.
	 *  Returns the number of real arcs and inserts in *rest_arcs all the arcs of  grid.
	 *  It is used to give the argument of assign_lael_list_arcs */
	
	list_nodes* temp = NULL;
	int width = gr->dims[0];
	int height = gr->dims[1];
	int r = 0;
	int c = 0;
	
	/* Searches a node to begin the visit */
	
	while ( r < height && ( temp == NULL || temp->node->type != 1 )) {
		c = 0;
		while (c < width && ( temp == NULL || temp->node->type != 1 )){
				temp = gr->cells[r][c];
				c ++;
		}
		r ++;
	}

	/* In list_nodes temp there is a real node or nothing */

	if (test == 1) printf("Creates real arcs - Beginning\n");
	
	if ( temp != NULL ){ 
		list_nodes* to_visit_nodes = NULL;		/* It is the set of nodes to visit */
		list_nodes* to_visit_real_nodes = copy_list_nodes( temp ); /* It is the set of real_nodes to visit, the first set is temp lists */
		list_nodes* neighbours_to_visit = NULL;
		list_nodes* visited_nodes = NULL;		 	/* List of visited nodes*/
		list_nodes* visited_real_nodes = NULL; 		/* List of visited real nodes */

		list_real_arcs* real_arcs = NULL;// = malloc( sizeof( list_real_arcs ) );					/* List of real_arc to return */
		list_real_arcs* rest_real_arcs = NULL;

		node* final_node;
		node* previous_node;
		node* current_node;							/* Current node */
		node* current_real_node = NULL;					/* Current real node*/
		
		int number_real_arcs = 0; 
		//printf("Starting node\n");
		//print_list_nodes(temp);
		
		int number_nodes;
		int first = 0;
		/* It begins from the real nodes in the first not free cell */
		real_arcs = malloc(sizeof( list_real_arcs ));
		
		while ( to_visit_real_nodes != NULL && level != 0){ 				/* It stops when there isn't any real node to analize */
			current_real_node = to_visit_real_nodes->node;  /* Current real node, it will be the first node in the real arc */
			
			neighbours_to_visit = copy_list_nodes( current_real_node->neighbours ); /* Nodes to visit are the neighbours of the real node*/
			
			insert_node( &visited_nodes, current_real_node );	  /* Inserts real node in visited nodes list */
			insert_node( &visited_real_nodes, current_real_node); /* Inserts real node in visited real nodes list */
			//printf("Nodo reale %i,%i\n", current_real_node->position[0], current_real_node->position[1]);
			
			list_nodes* first_neighbours_to_visit = neighbours_to_visit;

			while ( neighbours_to_visit != NULL ){   /* Neighbours of real node */
				//printf("Vicini Nodo reale\n");
				//print_list_nodes(neighbours_to_visit);
				
;
				number_nodes = 1;
				
				if ( !is_in_list_nodes( visited_nodes, neighbours_to_visit->node)){ /* Verifies if neighbour node was visited */
					
					
					if (!first) {
						list_real_arcs* temp_lra = real_arcs; 
						real_arcs->next = malloc( sizeof( list_real_arcs ) ); 			/* Creation of the arc memory space*/
						
						real_arcs = real_arcs->next;
						rest_real_arcs = real_arcs;
						free(temp_lra);
						temp_lra = NULL;
						first = 1;
					}
					else {
						real_arcs->next = malloc( sizeof( list_real_arcs ) ); 			/* Creation of the arc memory space*/
						real_arcs = real_arcs->next;
					}
						

					
					real_arcs->n_start = current_real_node;						/* Sets the n_start node of the real arc */
					real_arcs->nodes = NULL;
					real_arcs->next = NULL;
					insert_node( &( real_arcs->nodes ), current_real_node );	/* Sets the first node of the real arc list_nodes */
				
					previous_node = current_real_node;
					//printf("Nodi da visitare");
					
					insert_node(&to_visit_nodes, neighbours_to_visit->node );
					
					while ( to_visit_nodes != NULL  && to_visit_nodes->node->type != 1){ 							/* It stops only when a node is a real node */
							current_node = to_visit_nodes->node; 						/* Current not real node */	
							//printf("Nodo %i,%i\n", current_node->position[0], current_node->position[1]);
							
							if ( !is_in_list_nodes( visited_nodes, current_node ) ){	/* If node isn't in visited list, it inserts the neighbours and deletes the current node */
								list_nodes* neighs = copy_list_nodes( current_node->neighbours );
								delete_node_from_list( &neighs, previous_node );				/* Doesn't analize the current node*/
								
								insert_node( &( real_arcs->nodes ), current_node );
								number_nodes ++;
								
								insert_node(&visited_nodes, current_node);
								insert_node_at_top( &to_visit_nodes , neighs->node );
								//print_list_nodes(neighs);
								delete_node_from_list( &to_visit_nodes, current_node );
								free_list_nodes(neighs, 0);
								neighs = NULL;
								//printf("Interno\n");
								
								
								
								
							}
							
						
						else
							to_visit_nodes = to_visit_nodes->next;
						previous_node = current_node;
					}
					
					 /* Deletes start real node from to_visit real nodes list*/
					if (to_visit_nodes != NULL) 
						final_node = to_visit_nodes->node;
					else
						final_node = current_real_node;				
					free_list_nodes(to_visit_nodes, 0);
					to_visit_nodes = NULL;
					
					if (  !is_in_list_nodes( visited_real_nodes, final_node ) ){
						list_nodes* real_neighs = final_node->neighbours;
						
						while ( real_neighs != NULL && is_in_list_nodes(visited_nodes, real_neighs->node) )
							real_neighs = real_neighs->next;
							
						if ( real_neighs != NULL )
							insert_node( &to_visit_real_nodes, final_node );		  /* Inserts new real nodes in the real nodes to visit */
					}
					
					insert_node( &( real_arcs->nodes ), final_node ); 	  	  /* Inserts the (last) node in list_nodes of real arc*/
					real_arcs->n_end = final_node;						  	  /* Sets arc end node */
					real_arcs->length = number_nodes;

				
					number_real_arcs ++;
					//real_arcs = real_arcs->next;	
				}
				neighbours_to_visit = neighbours_to_visit->next;
				
				
			}

			delete_node_from_list( &to_visit_real_nodes, current_real_node );
			free_list_nodes(first_neighbours_to_visit, 0);
			first_neighbours_to_visit = NULL;
			neighbours_to_visit = NULL;
			if (level == 1) level = 0;
			
		}
		free_list_nodes(visited_nodes,0);
		visited_nodes = NULL;
		free_list_nodes(visited_real_nodes,0);
		visited_real_nodes = NULL;
		
		real_arcs = NULL;
		//print_real_arcs(rest_real_arcs);
		return rest_real_arcs;
		
	}
	else {
		if (test == 1) printf("The grid is empty\n");
	
	return 0;
	}
}


int wide_visit( grid* gr, list_arcs** rest_arcs) {
	/* Takes a node and visit alls his neighbours in a wide visit */
	/* Returns the number of real arcs and insert in *rest_arcs all the arcs of the grid */
	list_nodes* temp = NULL;
	
	int width = gr->dims[0];
	int height = gr->dims[1];
	int r = 0;
	int c = 0;
	
	while ( r < height && temp == NULL ) {
		c = 0;
		
		while (c < width && temp == NULL){
				temp = gr->cells[r][c];
				c ++;
		}
		r ++;
	}
	node* n;

	if ( temp != NULL){
		n = temp->node;
	
		list_nodes* to_visit = copy_list_nodes(n->neighbours) ;	/* It is the set of the node to visit */

		list_nodes* visited = NULL;
		list_arcs* all_arcs = NULL;
		
		node* current;
		
		int number_real_arcs = 0; 

		while ( to_visit != NULL ){
			current = to_visit->node; /* Current node */	
			
			if ( !is_in_list_nodes( visited, current ) ){	/* If node isn't in visited list, it inserts the neighbours and deletes the current node */
				//list_nodes* neighs = copy_list_nodes( current->neighbours );
				//printf("Noaho\n");
				
				list_arcs* arcs = make_arcs( current, current->neighbours, visited );

				to_visit = conc_nodes(current->neighbours, to_visit);

				conc_list_arcs2(arcs, &all_arcs);
				//free_list_arcs(arcs);
				

				insert_node(&visited, current);
			
			}
			delete_node_from_list( &to_visit, current );
			
		}
		free_list_nodes(visited, 0);
		visited = NULL;
		
		*rest_arcs = all_arcs;
		
		return number_real_arcs-1;
	}
	else {
		if (test == 1) printf("The grid is empty\n");
	
	return 0;
	}
}

void prepare_list_arcs(list_arcs* arcs){
	/* Takes all arcs and exchanges n1 node with n2 node if the coordinates of n1 are greater than n2.
	 * It is used to understand if there are two different cells linked by more than one arcs */
	list_arcs* temp = arcs;
	node* temp_node;
	int x1, y1, x2, y2;
	
	while ( temp != NULL ){
		x1 = temp->arc->n1->position[0];
		y1 = temp->arc->n1->position[1];
		x2 = temp->arc->n2->position[0];
		y2 = temp->arc->n2->position[1];		
	
		if (x1 > x2 || (x1 == x2 && y1 > y2) ){
			temp_node = NULL;
			temp_node = temp->arc->n1;
			temp->arc->n1 = temp->arc->n2;
			temp->arc->n2 = temp_node;
		}
		temp = temp->next;
	}
}

int compare_arcs(const arc* a1, const arc* a2){
	/* Function used to sort arcs*/
	int x1, y1, x2, y2;
	x1 = a1->n1->position[0];
	y1 = a1->n1->position[1];
	x2 = a1->n2->position[0];
	y2 = a1->n2->position[1];
	
	int x_1, y_1, x_2, y_2;
	x_1 = a2->n1->position[0];
	y_1 = a2->n1->position[1];
	x_2 = a2->n2->position[0];
	y_2 = a2->n2->position[1];
	
	int rest;
	
	if ( x1 < x_1 || ( x1 == x_1 && y1 < y_1 ) || ( x1 == x_1 && y1 == y_1 && x2 < x_2 ) || ( x1 == x_1 && y1 == y_1 && x2 == x_2 && y2 < y_2 ))
		rest = -1;
	else if ( x1 == x_1 && y1 == y_1 && x2 == x_2 && y2 == y_2 )
		rest = 0;
	else rest = 1;
	return rest;
}


void create_path(grid* gr, node* n1, node* n2, int vert){
	/* Creates a path with all the neighbourhoods linking two nodes. "vert" is a boolean which indicates 
	 * if the path is in vertical direction or horizontal when the nodes are not straight, but now it isn't useful, only straight is used.
	 * It is used to create a new grid manually */
	int r_1; 
	int c_1;
	int r_2;
	int c_2;
	
	int diff_horiz = abs( n1->position[1] - n2->position[1] );
	int diff_vert = abs( n1->position[0] - n2->position[0] );
	
	node* n;
	
	
	node *temp1, *temp2;
	
	int r,c;
	
	if ( diff_vert > 0 && diff_horiz == 0 ){
		if ( n1->position[0] > n2->position[0] ){
			temp1 = n1;
			temp2 = n2;
		}
		else {
			temp1 = n2;
			temp2 = n1;
		}
		
		node* previous = temp2;

		r_1 = temp1->position[0];
		c_1 = temp1->position[1];
		r_2 = temp2->position[0];
		c_2 = temp2->position[1];
	
		r = r_2 + 1;

		while (r < r_1 ){
			n = create_node("0", 2);
			put_node_in_cell( n , gr, r, c_1  );
			
			make_neighbour(n, previous);
			previous = n;
			r ++;
		}
		make_neighbour(temp1, previous);
	}
	else 
	if (diff_vert == 0 && diff_horiz > 0){ /* The node are both in horizontal direction*/
		if ( n1->position[1] > n2->position[1] ){
			temp1 = n1;
			temp2 = n2;
		}
		else {
			temp1 = n2;
			temp2 = n1;
		}
		
		node* previous = temp2;
		
		r_1 = temp1->position[0];
		c_1 = temp1->position[1];
		r_2 = temp2->position[0];
		c_2 = temp2->position[1];
			
		c = c_2 + 1;

		while (c < c_1 ){
			n = create_node("0", 2);
			put_node_in_cell( n , gr, r_1, c  );
			
			make_neighbour(n, previous);
			previous = n;
			c ++;
		}
		make_neighbour(temp1, previous);
		
	}
}

int is_neighbour( node* n1, node* n2){
	/* It verifies if n1 is neighbour of n2 (it is not important to demonstrate the viceversa because it is obvious */
	int is_neigh = is_in_list_nodes(n1->neighbours, n2 ) ;
	return is_neigh;
}

int are_all_neighbours(list_nodes *list, node* n, int type){
	/* It verifies if all nodes of list are neighbours of n and of the same type.
	 * If type < 0 there isn't a check on node type */
	int are_all_neigh = 1;
	
	while( list != NULL){
	
		if (! is_neighbour( list->node, n ) || ( list->node->type != type && type > 0 ))
			are_all_neigh = 0;
			
		list = list->next;
	}
	return are_all_neigh;
}

int is_free_cell( grid* gr, int x, int y){
	/* It verifies if an x,y cell in a grid is free */
	if ( x >= 0 && y >= 0 && x < gr->dims[1] && y < gr->dims[0] ) 
		return  gr->cells[x][y] == NULL ;
	else
		return 0;
}

int real_nodes_number(grid* gr){
	int width = gr->dims[0];
	int height = gr->dims[1];
	int r, c;
	int real_nodes_counter = 0;
	
	for ( r = 0; r < height; r++ )
		
		for ( c = 0; c < width; c++ ){
			list_nodes* nodes = gr->cells[r][c];
			
			if ( nodes != NULL && nodes->node->type == 1)
				real_nodes_counter ++;
		}
	return real_nodes_counter;
}

int neighbours_number(node* n1){
	/* Returns the number of neighbours of the node n1 */
	list_nodes * temp = n1->neighbours;
	int i = 0;
	
	while (temp != NULL){
		temp = temp->next;
		i ++;
	}
	return i;
}

int verify_labels( node* n, list_nodes *nodes){
	/* Verifies if all nodes have one limit-node equal to n one.
	 * It is used to put a constraint in the moving of the nodes in the cell */

	list_nodes* temp_nodes = nodes;

	int verify_lab = 0;

	while ( temp_nodes != NULL && (  temp_nodes->node->n1 == n->n1 || temp_nodes->node->n2 == n->n1)){
		//print_labels( temp_nodes->node );
		temp_nodes = temp_nodes->next;
		
	}
	if (temp_nodes != NULL){
		temp_nodes = nodes;
		
		while ( temp_nodes != NULL && (  temp_nodes->node->n2 == NULL ||temp_nodes->node->n1 == n->n2 || temp_nodes->node->n2 == n->n2))
			temp_nodes = temp_nodes->next;
			
		if (temp_nodes != NULL) 
			verify_lab = 0;
		else
			verify_lab = 1;
	}
	else
		verify_lab = 1;

	return verify_lab;	/* If temp_nodes is NULL it means that in all nodes labels there isn't a label equal to n labels*/

}

void assign_label_new_bend(node* n){

	if (n->type == 2){
		node* n1 = n->neighbours->node;
		node* n2 = n->neighbours->next->node;
		node* temp = n1;
		node* previous = n;
		
		while (temp->type != 1){
			
			if (temp->neighbours->node != previous){
				previous = temp;
				temp = temp->neighbours->node;
			}
				
			else{
				previous = temp;
				temp = temp->neighbours->next->node;
			}
		}
		
		temp = n2;
		
		previous = n;
		
		while (temp->type != 1){
			
			if (temp->neighbours->node != previous){
				previous = temp;
				temp = temp->neighbours->node;
			}
				
			else{
				previous = temp;
				temp = temp->neighbours->next->node;
			}
		}
		n->n1 = n1;
		n->n2 = n2;		
	
	}
	else{
		printf("Node is not a bend\n");
	
	}
}

int move_real_node(grid* gr, node* n, int x, int y){
	/* 
	Precondition:	
		1 - Node is real node
		2 - Cell (x, y) isn't the same cell of n
		3 - Cell (x, y) is a "near" n position
		4 - Destination cell (x,y) is free or contains nodes which are all not real nodes neighbours of n
		
	Postcondition:	
		1 - Creation of new bends or segments, each one for old neighbours of n (but not those in destination cell)
		1 or 2 - Movement of node n in destination cell ( delete from starting cell, insertion in destination cell )
		
		All these postconditions still consists in replacing/recreatings neighbourhoods
	*/
	int created = 0;
	
	int x_1 = n->position[0];
	int y_1 = n->position[1];
	int positions[4][2];
	near_positions(gr, positions, x_1, y_1);	/* Put in "positions" the coordinates of cell around node n position*/

	/* Precondition values */
	int is_real_node = n->type == 1;
	int same = x_1 == x && y_1 == y;
	int is_in_pos = is_in_positions(positions, 4, x, y);
	
	int are_all_neigh = are_all_neighbours( gr->cells[x][y], n, -1 );

	list_nodes* temp = get_neighbours(n, x, y);
	int is_bend  = (temp != NULL && temp->node->type == 2);
	free_list_nodes(temp, 0);
	temp = NULL;
	
	int is_free = is_free_cell( gr, x, y );

	if (test == 1) printf("MOVES REAL NODE - Precond-> Real:%i, Same cell:%i, Near Pos:%i, All Neigh:%i,Is Bend:%i Is Free:%i\n", is_real_node, !same, is_in_pos , are_all_neigh, is_bend, is_free) ;
	
	if ( is_real_node && !same && is_in_pos && ( ( are_all_neigh && is_bend ) || is_free ) ){
		/* 1 - Creation of new bends or segments */
		
		list_nodes* temp_neigh = copy_list_nodes(n->neighbours);
		list_nodes* neigh = temp_neigh;
		clear_node_neighbours(n);	/* Deletes all neighbours pointers of the node n*/					

		while ( neigh != NULL  ){ /* Scan all neighbours of node n */
							
			if ( neigh->node->position[0] != x || neigh->node->position[1] != y ) {
				delete_node_from_list( &(neigh->node->neighbours), n );	/* Deletes node n from its neighbours not in destination cell */
				node* new = create_node("2", 2); 			/* Creates a node for each neighbours not in destination cell */
				
				new->type = 2;
				created = 1;
				put_node_in_cell( new, gr, x_1, y_1); 			/* Puts new node in list_nodes of the start cell*/
				make_neighbour(neigh->node, new); 			/* Redefinition of the neighbours*/
				make_neighbour(new, n);
				//new->n1 = n;
				
				if (neigh->node->type != 1){
					new->n1 = neigh->node->n1;
					new->n2 = neigh->node->n2;
				}
				else{
					new->n1 = n;
					new->n2 = neigh->node;
				}
				//new->n2 = neigh->node;
				//assign_label_new_bend(new);
			}
			neigh = neigh->next;
		}
		free_list_nodes(temp_neigh,0 );
		temp_neigh = NULL;
		/* 2 - Delete of nodes in destination cell*/
		
		list_nodes* dest_nodes = gr->cells[x][y];	/* Nodes in destination cell*/
		list_nodes* all_neighbours = NULL;		/* List of nodes which we will use to define new neighbourhoods*/
		list_nodes* neighs;
		
		while ( dest_nodes != NULL ){			/* Scan the nodes in destination cell */
			neighs = dest_nodes->node->neighbours;
			
			while( neighs != NULL ){ 		/* Scan the neighbours of each node we must substitute in destination cell */

				if (neighs->node->position[0] != x_1 || neighs->node->position[1] != y_1 ){
					insert_node(&(all_neighbours), neighs->node);
					delete_node_from_list(&(neighs->node->neighbours), dest_nodes->node);	/* Deletes the node from its neighbours' list */
					delete_node_from_list( &(gr->cells[x][y]), dest_nodes->node );		/* Deletes node from cell*/
					
					created = 2;
				}
				neighs = neighs->next;
			}
			dest_nodes = dest_nodes->next;
		}

		neighs = NULL;
		/* 3 - Movement of node n in destination cell*/
		
		delete_node_from_list( &(gr->cells[x_1][y_1]), n ); /* Deletes node n from  cell start cell */
		put_node_in_cell( n, gr, x, y);							/* Move n in destination cell*/
		list_nodes* first = all_neighbours;
		while ( all_neighbours != NULL ){ 						/* Neighbours redefinition of destination cell*/
			make_neighbour( all_neighbours->node, n);
			all_neighbours = all_neighbours->next;
			
		}
		free_list_nodes( first, 0 );	/* Clears the list */
		first = NULL;
		if (test == 1)  printf("\tMOVES REAL NODE - From cell (%i, %i) to cell (%i, %i) is OK\n", x_1, y_1, x, y);
	}
	else {
		if (test == 1)  printf("\tMOVES REAL NODE - From cell (%i, %i) to cell (%i, %i) is not possible\n", x_1, y_1, x, y);
		created = -1;
	}
	
	return created;
}


int move_corner(grid* gr, node*n, int x, int y, int var_x, int var_y ){
	/* Moves a bend in the opposite cell.
	*   It is used by move_bend (having the same precondition).
	*   x e y are destination coords, var_x, var_y identifies which type of corner is:
	*   1,  1 North-West
	*-  1,  1 South-West
	*  -1, -1 South-East
	*   1, -1 North-East) */
	
	int x_1 = n->position[0];
	int y_1 = n->position[1];

	int moved = 0;
	
	
	if ( ((x - x_1) == 0 && (y - y_1) == var_y) ) {  /* N is at Top-Left bend */
		list_nodes* nears2 = get_neighbours( n, x_1, y_1+var_y );
		
		if (nears2 != NULL){
			node* near2 = nears2->node;
			free_list_nodes(nears2, 0);
			nears2 = NULL;
			if (near2->type != 1 && neighbours_number( near2 ) == 2){
				list_nodes* dest_nears = get_neighbours(near2, x_1+var_x, y_1+var_y);
				
				if ( dest_nears != NULL ){
					node* dest = dest_nears->node;
					
					free_list_nodes(dest_nears, 0);
					dest_nears = NULL;
					list_nodes* nears1 = get_neighbours( n, x_1+var_x, y_1);
					if ( nears1 != NULL ){
						node* near1 = nears1->node;
						free_list_nodes(nears1, 0);
						nears1 = NULL;
						delete_node_from_list(&(gr->cells[x_1][y_1]), n  );
						delete_node_from_list(&(gr->cells[x_1][y_1+var_y]), near2  );
						
						delete_node_from_list(&(near1->neighbours), n );
						delete_node_from_list(&(near2->neighbours), n );
						delete_node_from_list(&(dest->neighbours), near2 );
						delete_node_from_list(&(n->neighbours), near2 );
						free_node(&n, 1);
						n = NULL;
						free_node(&near2, 1);
						near2 = NULL;
						make_neighbour( dest, near1 );
						moved = 1;
					}
				}
			}
		}
	}
	else{
		
		if ( (x - x_1) == var_x && (y - y_1) == 0 ){
			list_nodes* nears1 = get_neighbours( n, x_1+var_x, y_1 );
			
			if (  nears1 != NULL){
				node* near1 = nears1->node;
				free_list_nodes(nears1, 0);
				nears1 = NULL;
				if (near1->type != 1 && neighbours_number( near1 ) == 2){
					list_nodes* dest_nears = get_neighbours(near1, x_1+var_x, y_1+var_y);
					
					if ( dest_nears != NULL ){
						node* dest = dest_nears->node;
						free_list_nodes(dest_nears, 0);
						dest_nears = NULL;
						list_nodes* nears2 = get_neighbours( n, x_1, y_1+var_y);
						
						if ( nears2 != NULL ){
							node* near2 = nears2->node;
							free_list_nodes(nears2, 0);
							nears2 = NULL;
							delete_node_from_list(&(gr->cells[x_1][y_1]), n  );
							delete_node_from_list(&(gr->cells[x_1+var_x][y_1]), near1  );
							
							delete_node_from_list(&(near2->neighbours), n );
							delete_node_from_list(&(near1->neighbours), n );
							delete_node_from_list(&(dest->neighbours), near1 );
							delete_node_from_list(&(n->neighbours), near1 );
							free_node(&n, 1);
							n = NULL;
							free_node(&near1, 1);
							near1 = NULL;
							make_neighbour( dest, near2 );
							moved = 1;
						}
					}
				}
			}
			
			
		}
	}
	if ( !moved //&& ( consider_free) || is_free_cell(gr, x_1+var_x, y_1+var_y) ) 
			&& has_neighbour(n, x_1, y_1+var_y ) && has_neighbour(n, x_1+var_x, y_1) &&
			(verify_labels(n, gr->cells[x_1+var_x][y_1+var_y]) || verify) && !is_real_node_in_cell(gr, x_1+var_x, y_1+var_y) ){
		/* No real nodes must be in new node cell*/
		delete_node_from_list(&(gr->cells[x_1][y_1]), n  );
		put_node_in_cell(n, gr, x_1+var_x, y_1+var_y);
		moved = 1;
		
	}

	
	return moved;
}

int move_bend(grid* gr, node* n, int x, int y){
	/* Precondition:
		1 - Node n is of type 1
		2 - Node n has two neighbours
		3 - One or both among the two neighbours is in destination cell (x, y)
		4 - The two neighbours and the node n form a rect angle or a skipnot
		
	   Postcondition:
	   	1.1 - Move the node n in "opposite" position
		1.2 - Skipnot is removed
	   	
	*/
	
	int created = 0;
	
	/* Precondition values */
	int x_1 = n->position[0];
	int y_1 = n->position[1];
	
	int is_segment = (n->type == 2);		/* Node n isn't a real node */
	int two_neigh = neighbours_number( n );		/* Node n has two neighbours*/
	int dest_neigh = has_neighbour(n, x, y);	/* One neighbour is in destination cell */
	
	if (test == 1) printf("MOVES BEND NODE - Precond-> Is segment:%i, Two neigh:%i, Dest neigh:%i - From (%i, %i) to (%i, %i) \n", is_segment, two_neigh , dest_neigh, x_1, y_1, x, y) ;

	if ( is_segment && ( two_neigh==2 ) && dest_neigh ){
		int var_x;
		int var_y;
		node* n1 = n->neighbours->node;
		node* n2 = n->neighbours->next->node;
		//int verify = 0;
		int moved = 0;
		
		if ( n1->position[0] == x && n1->position[1] == y && n2->position[0] == x && n2->position[1] == y ){
			
			if ( 1 ){				/* No real nodes must be in new node cell*/
				delete_node_from_list( &(gr->cells[x_1][y_1]), n );/* Deletes node from cell*/
				delete_node_from_list( &(gr->cells[x][y] ), n1 );
				delete_node_from_list( &(gr->cells[x][y] ), n2  );

				if ( n1->type == 1 || n2->type == 1 ) {
					n->type = 1;
				}
				
				put_node_in_cell(n, gr, x, y);
				delete_node_from_list(&(n1->neighbours), n );
				delete_node_from_list(&(n2->neighbours), n );
				
				list_nodes* all_neighs = NULL;
				list_nodes** pointer_all_neighs = &all_neighs;		
				list_nodes* neighs2;
				list_nodes* neighs = n->neighbours;	/* All the neighbours of node n */
				
				while ( neighs != NULL ){		/* Scans the neighbours of node n*/
					if (neighs->node == n1 || neighs->node == n2){
						neighs2 = neighs->node->neighbours;	/* Neighbours of the node which occupied destination cell*/
	
						while ( neighs2 != NULL ){
					
							if ( neighs2->node != n ){
								delete_node_from_list(&(neighs2->node->neighbours), neighs->node);
								insert_node( &( all_neighs ) ,  neighs2->node );
							}
							neighs2 = neighs2->next;
						}
					}
					neighs = neighs->next;
				}
				delete_node_from_list(&(n->neighbours), n1 );
				delete_node_from_list(&(n->neighbours), n2 );
				free_list_nodes(n1->neighbours,0);
				n1->neighbours = NULL;
				free_list_nodes(n2->neighbours,0);
				n2->neighbours = NULL;
				free_node(&n1, 0);
				n1 = NULL;
				free_node(&n2, 0);
				n2 = NULL;
				
				while ( all_neighs != NULL ){
					make_neighbour( n, all_neighs->node );
					all_neighs = all_neighs->next;
				}
				free_list_nodes(*pointer_all_neighs, 0);
				*pointer_all_neighs = NULL;
				moved = 1;
			}
		}
		else {
			var_x = 1;
			var_y = 1;
			/* n--------near2
			 * |          
			 * |          
			 * |          
			 * |          
			 * near1    dest */
			int moved = move_corner(gr, n, x, y, var_x, var_y);
			
			var_x = -1;
			var_y = 1;
			/* near1    dest
			 * |          
			 * |          
			 * |          
			 * |          
			 * n--------near2 */
			if (!moved) moved = move_corner(gr, n, x, y, var_x, var_y);
			
			var_x = -1;
			var_y = -1;
			/* near1------n
			 *            |   
			 *            |
			 *            |
			 *            |
			 *          near2 */
			if (!moved) moved = move_corner(gr, n, x, y, var_x, var_y);
			
			var_x = 1;
			var_y = -1;
			/*          near2
			 *            |   
			 *            |
			 *            |
			 *            |
			 * near1------n */
			
			if (!moved) moved = move_corner(gr, n, x, y, var_x, var_y);
		}

		if (test == 1) if ( moved) printf("\tMOVES BEND NODE - From cell (%i, %i) to cell (%i, %i) is OK\n", x_1, y_1, x, y);
		created = 0;
	}
	else {
		if (test == 1)  printf("\tMOVES BEND NODE - From cell (%i, %i) to cell (%i, %i) is not possible\n", x_1, y_1, x, y);
		created = -1;
	}
	
	return created;
}


int move_node(grid* gr, node* n, int x, int y){
	/* Moves a node (real or bend node) n in x, y destination cell */
	
	int created = 1;
	int x_1 = n->position[0];
	int y_1 = n->position[1];
	
	while (created == 1){
		if (n->type != 1 && n->type != 2)
			printf("nooooooooooooooooooooo\n");
		if ( n->type == 2 ){
			move_bend( gr, n, x, y);
			created = 0;
			
		}
		else 
		
			created = move_real_node( gr, n, x, y);
			
			//if (created){
				//list_real_arcs* temp_real_arcs = create_list_arcs( gr, 1 );
				//assign_label_list_arcs( temp_real_arcs );
				//free_list_real_arcs(temp_real_arcs);
			//}
		
			//list_nodes* created_nodes = get_neighbours(n, x_1, y_1);
			//list_nodes* first_created_nodes = created_nodes;
			//list_nodes* pointer_created_nodes = created_nodes;
			
			/*if (created_nodes != NULL)
				n = created_nodes->node;
			if (created_nodes != NULL) {
				
				while ( created_nodes != NULL ) {
					created = move_node(gr, created_nodes->node, x, y);
					created_nodes = created_nodes->next;
				}
			}*/
			
			///free_list_nodes(first_created_nodes, 0);
		
		 
	}

	return created;
}

void move_nodes(grid* gr, int x, int y, char* direction){
	/* Moves all nodes in x+var_x, y+var_y destination cell.
	 * var_x, var_y are definied by direction ("Up", "Down", "Left", "Right") */
    int var_x;
    int var_y;

    if ( !strcmp( direction, "Up" ) ){
    	var_x = -1;
    	var_y = 0;
    	
    }
    else if ( !strcmp( direction, "Down" ) ){
    	var_x = 1;
    	var_y = 0;
    	
    }
    else if ( !strcmp( direction, "Left" ) ){
    	var_x = 0;
    	var_y = -1;
    }
    else if ( !strcmp( direction, "Right" ) ){	
    	var_x = 0;
    	var_y = 1;
    }
    else {
    	var_x = 0;
    	var_y = 0;
    }
	if (gr->cells[x][y] != NULL){
	    list_nodes* temp = gr->cells[x][y];
	    list_nodes* next;
	    
	    while ( temp != NULL ){
	    	move_node( gr, temp->node, x+var_x, y+var_y );
	    	temp = temp->next;
	    }
	}
};

void move_down( grid* gr ){
	int height = gr->dims[1];
	int r;

	for ( r = 0; r < height-1; r++ ){
		move_row(gr, r, r+1, 0);
	}
}

void move_up( grid* gr ){
	int height = gr->dims[1];
	int r;

	for ( r = height; r > 1; r--){
		move_row(gr, r, r-1, 0);
	}
}

void move_right( grid* gr ){
	int width = gr->dims[0];	
	int c;
	
	for ( c = 0; c < width-1; c++){
		move_column( gr, c, c+1, 0 );
	}

}

void move_left( grid* gr ){
	int width = gr->dims[0];
	int c;

	for ( c = width; c > 1; c--){
		move_column( gr, c, c-1, 0 ) ;
	}
}
void move_row(grid * gr, int row, int new_row, int double_direction){
	/* Move all nodes of a row at new row.
	 * If double direction is 1, it repeat the movement 
	 * scanning row nodes in reversing order */
	int r,c;	
	int width = gr->dims[0];
	
	if (row < new_row ){
		
		for ( r = row + 1; r <= new_row; r++ ) {
			
			for ( c = 0; c < width; c++ )			
				move_nodes( gr, r-1, c, "Down" );
				
			if ( double_direction ){
			
				for ( c = width - 1; c >= 0; c-- )		
					move_nodes( gr, r-1, c, "Down" );
			}
		}
	}
	else 
		if (row > new_row){ 
		
			for ( r = row - 1; r >= new_row; r-- ) {
				
				for ( c = 0; c < width; c++ )
					move_nodes( gr, r+1, c, "Up" );
					
				if ( double_direction ){
					
					for ( c = width - 1; c >= 0; c-- )			
						move_nodes( gr, r+1, c, "Up" );
				}

			}
		}
}
void move_column(grid* gr, int column, int new_column, int double_direction){
	/* Move all nodes of a column at new column.
	 *   If double direction is 1, it repeat the movement 
	 *   scanning column nodes in reversing order */
	int r, c;
	int height = gr->dims[1];

	if ( column < new_column )
		
		for ( c = column + 1; c <= new_column; c++){
			
			for ( r = 0; r < height; r++ )
				move_nodes( gr, r, c-1, "Right" );
			
			if ( double_direction ){
				
				for ( r = height - 1; r >= 0; r-- )
					move_nodes( gr, r, c-1, "Right" );
			
			}
		}			
	
	else 
		if (column > new_column)

			for (c = column - 1; c >= new_column; c--){
				
				
				for ( r = 0; r < height; r++ )
					move_nodes( gr, r, c+1, "Left" );
					
				if ( double_direction ){
					
					for ( r = height - 1; r >= 0; r-- )
						move_nodes( gr, r, c+1, "Left" );
				
				}

			}
		

}

void move_to_row(grid* gr, int from_row, int to_row, int double_direction){
	/* Move all nodes towards to_row.
	 *   If double direction is 1, it repeat the movement 
	 *   scanning row nodes in reversing order */
	int r;
	
	if ( from_row < to_row )
		for ( r = to_row-1; r >= from_row; r-- ){
			move_row( gr, r, to_row, double_direction );
		} 
		
	else
		if ( from_row > to_row )
			for ( r = to_row+1; r <= from_row; r++ ){
				move_row( gr, r, to_row, double_direction );
			} 
}

void move_to_column(grid* gr, int from_column, int to_column, int double_direction){
	/* Move all nodes towards to_column.
	 *   If double direction is 1, it repeat the movement 
	 *   scanning column nodes in reversing order */
	int c;
	
	if ( from_column < to_column)
	
		for ( c = to_column-1; c >= from_column; c-- ){
			move_column( gr, c, to_column, double_direction );
		}
	else
		if ( from_column > to_column )
			for ( c = to_column+1; c <= from_column; c++ ){
				move_column( gr, c, to_column, double_direction );
			}
}

int get_area( grid* gr, int* limits ){
	/* Calculates area of a grid and returns row and column limits
	 *  where there are graph borders*/
	int width = gr->dims[0];
	int height = gr->dims[1];
	
	int r, c, r_min, r_max, c_min, c_max, free_columns, free_rows;
	
	r_min = height-1;
	c_min = width-1;
	c_max = 0;
	r_max = 0;
	
	for ( r = 0; r < height; r++ ){
		c = 0;
		free_columns = 1;
		
		while ( c < width && free_columns == 1){
		
			if ( !is_free_cell(gr, r, c) )
				free_columns = 0;
			c ++;
		}
		if ( !free_columns ){
			
			if ( r <= r_min ) 
				r_min = r;
				
			if ( r >=r_max )
				r_max = r;
		}
	}
	
	for ( c = 0; c < width; c++ ){
		r = 0;
		free_rows = 1;
		
		while ( r < height && free_rows == 1){
		
			if ( !is_free_cell(gr, r, c) )
				free_rows = 0;
			r ++;
		}
		
		if ( !free_rows ){
			
			if ( c <= c_min ) 
				c_min = c;
				
			if ( c >= c_max )
				c_max = c;
		
		}
	}
	limits[0] = r_min;
	limits[1] = r_max;
	limits[2] = c_min;
	limits[3] = c_max;
	long int area = (c_max - c_min) * (r_max - r_min);
	printf("Area = %ld    Estremi griglia = N.O.(%i, %i), S.E.(%i, %i)\n", area, limits[2], limits[0], limits[3], limits[1] );
	return area;
}

int verify_same_position( node*n ){
	/* Scans all neighbours and verifies if all ones are in the same position */
	
	list_nodes* neighs = n->neighbours;
	//print_list_nodes(neighs);

	int x = neighs->node->position[0];
	int y = neighs->node->position[1];
	
	while (neighs != NULL && x == neighs->node->position[0] &&  y == neighs->node->position[1] && neighs->node->type != 1){
		neighs = neighs->next;
		
	}
	return neighs == NULL; /* If neighs is NULL then all neighbours are in the same position because the cicle has continued until the neighs was NULL*/
}

void retraction( grid* gr, node* n){
	/* If node n neighbours are all in the same position, it moves n towards neighbours position*/
	
	
	node* neigh = n;
	int created = 1;
	
	while ( created >= 1 && n->neighbours!= NULL && verify_same_position(n)){
		neigh = n->neighbours->node;			
		created = move_real_node(gr, n, neigh->position[0], neigh->position[1]);
	}
}

void scan_grid(grid* gr, int test_number){
	int width = gr->dims[0];
	int height = gr->dims[1];
	
	int count = 0;
	
	while ( count < test_number ){
		move_row(gr, 0, height-1, 0);
		move_column(gr, 0, width-1, 0);
		count ++;
	}
}

void retraction_from_grid(grid* gr){
	/* Scans all nodes in the grid trying to retract real nodes one */
	
	int width = gr->dims[0];
	int height = gr->dims[1];
	int c,r;
	list_nodes* temp_nodes;
	node* n;
	
	for ( r = 0; r < height; r++){
		
		for (c = 0; c < width; c++){
			temp_nodes = gr->cells[r][c];
			//print_list_nodes( temp_nodes );
			
			while ( temp_nodes != NULL){
				n = temp_nodes->node;
				
				if ( n->type ==1 && verify_same_position( n ))
					retraction(gr, n);

				temp_nodes = temp_nodes->next;
			}
		}
	}
	/*
	list_real_arcs* real_arcs = create_list_arcs(current_grid);
	print_real_arcs( real_arcs );
	node *n1, *n2;
	
	while (real_arcs != NULL ){
		n1 = real_arcs->n_start;
		n2 = real_arcs->n_end;
		
		if ( verify_same_position(n1))
			retraction(current_grid, n1);
		else if ( verify_same_position(n2))
			retraction(current_grid, n2);
		real_arcs = real_arcs->next;
	*/
}

int is_empty_row( grid* gr, int row ){
	/* Verifies if a row has only empty cells */
	
	int width = gr->dims[0];
	int i = 0;
	
	while (i < width && gr->cells[row][i] == NULL){
		i++;
	}
	
	int rest;
	
	if ( i == width ){
		rest = 1;	
	}
	else{
		rest = 0;
	}
	return rest;
}

int is_empty_column( grid* gr, int column ){
	/* Verifies if a column has only empty cells */
	
	int height = gr->dims[1];
	int i = 0;
	
	while (i < height && gr->cells[i][column] == NULL){
		i++;
	}
	
	int rest;
	
	if ( i == height ){
		rest = 1;	
	}
	else{
		rest = 0;
	}
	return rest;
}

int bends_number( grid* gr ){
	/* Calculates bends in a grid */
	
	list_nodes* temp = NULL;
	int width = gr->dims[0];
	int height = gr->dims[1];
	int r = 0;
	int c = 0;
	node* temp_node;
	int n = 0;
	int x_1, y_1;
	node *n1, *n2;
	
	while ( r < height ) {
		c = 0;
		
		while (c < width ){
			temp = gr->cells[r][c];
			
			while ( temp != NULL){
				temp_node = temp->node;
				
				if ( temp_node->type != 1){
					
					if ( neighbours_number(temp_node) == 2 ){/* A bend has two neighbours*/
						x_1 = temp_node->position[0];
						y_1 = temp_node->position[1];
						n1 = temp_node->neighbours->node;
						n2 = temp_node->neighbours->next->node;
					
						if ( abs( n1->position[0] - n2->position[0] ) == 1 && abs( n1->position[1] - n2->position[1]) ==1 ) {
							n++;
						}
					}
				}
				temp = temp->next;
			}
			c ++;
		}
		r ++;
	}
	return n;
}

int segments_length( list_real_arcs* real_arcs){
	/* Calculates length of arcs in a grid.
	 *  It needs real_arcs list */
	
	list_real_arcs* temp = real_arcs;
	int length = 0;
	
	while ( temp != NULL ){
		length = length + temp->length;
		temp = temp->next;
	}
	return length;
}

int verify_monopolyze( list_areas* first_areas, int steps ){
	/* Verifies if the area calculus outcomes the same value for MONOPOLYZE_FACTOR times*/
	
	list_areas* temp_areas = first_areas;
	
	int area_max = 0;
	
	while ( temp_areas != NULL ){
		
		if (temp_areas->area < area_max || area_max == 0 ) 
			area_max = temp_areas->area;
			
		temp_areas = temp_areas->next;
	}
	if (first_areas != NULL) printf("%d\n", first_areas->counter);

	return  first_areas == NULL || ! ( area_max == first_areas->area && first_areas->counter >= MONOPOLYZE_FACTOR);
}

 int update_area_stats( list_areas** first_areas,  int area_value ){
 	/* Inserts area_value in list of areas which it must be used to verifies if the alghoritm is minimizing */
 	
	int i = 0;
	 int temp_area;
	list_areas* areas = *first_areas;
	list_areas* temp_areas;
	
	while ( areas!= NULL && i < AREAS_MAX_SIZE && areas->area != area_value){
		areas = areas->next;
		i++;
	}
	
	if ( areas != NULL && i < AREAS_MAX_SIZE ){
		/* The list has area, we update it putting area at the top */
		temp_area = areas->area;
		delete_area_from_list(first_areas, areas->area );
		push_area(first_areas, temp_area);
		(*first_areas)->counter++;
		
	}
	else
		
		if ( areas == NULL && i < AREAS_MAX_SIZE ){
			/* The list hasn't area and it is just short */
			
			push_area(first_areas, temp_area);
			(*first_areas)->area = area_value;
			(*first_areas)->counter = 1;

			
		}
		else
			if (areas == NULL && i == AREAS_MAX_SIZE ){
				/* The list hasn't area but it is full, we delete last area*/
				push_area(first_areas, temp_area);
				(*first_areas)->counter = 1;
				(*first_areas)->area = area_value;
				temp_areas = *first_areas;
				
				while ( temp_areas != NULL ){
					
					if (temp_areas->next == NULL ){
						delete_area_from_list(first_areas, temp_areas->area);
					
					}			
					temp_areas = temp_areas->next;
				}	
			}
	temp_areas = (*first_areas);
	i = 0;
	while  ( temp_areas != NULL ){
		//printf("Area %i %ld %i\n", i, temp_areas->area, temp_areas->counter);
		temp_areas = temp_areas->next;
		i++;
	}
	if ( (*first_areas) != NULL)
		return (*first_areas)->area;
	else 
		return -1;
}

void elaborate_grid( grid* gr, config* cfg, stats* values ){
	/* Minimizes grid using the preferred alghoritm and parameters described in config structure.
	 *  It updates values stats */
	
	int area_before, area, bends_before, length_before;
	int i, step_counter, area_rest;
	int limits[4];// = malloc(sizeof(int)*4);
	
	/* Statistics before elaboration*/
	area_before = get_area(gr, limits );
	int top_row, down_row, left_col, right_col;

	bends_before = bends_number( gr );
	list_real_arcs* arcs = create_list_arcs(gr, -1);
	assign_label_list_arcs( arcs );
	length_before = segments_length(arcs);

	free_list_real_arcs(arcs);
	arcs = NULL;
	clock_t start = clock();
	
	/* Elaboration depends on alghoritm chosen in configuration */
	
	list_areas* areas = NULL;
	
	int d_r = -1;
	int d_c = -1;
	int rc;
	int clocks[4];

	switch ( cfg->alghoritm ){
		case 0:
			break;
		case 1:
		/* It alternates moving rows from 0 to last grid row and columns from 0 to last grid column.
		 * After moving it is a retraction. */
			col_ext = gr->dims[0] - 1;
			row_ext = gr->dims[1] - 1;
			
			rc = 0;
			area_rest = -1;

			
			step_counter = 0;
			int co = 0;
			
			while ( step_counter < cfg->args[0] && verify_monopolyze(areas, cfg->args[0]) ){
				//if (co >= row_ext && co >= col_ext)
				//	co = 0;
				if (co < row_ext)
					move_row(gr, 0, row_ext, 1 );
				if (co < col_ext)
					move_column(gr, 0, col_ext, 1 );
				co ++;
				//retraction_from_grid(gr);
				area_rest = get_area(gr, limits );
				update_area_stats( &areas, area_rest );
				step_counter ++;
				
			}
			
			retraction_from_grid(gr);
			break;
			
		case 2:

			/* It moves the nodes towards the center, moving row from top to center,
			 *  column from right to center, row from down to center, column from left to center */		
			
			step_counter = 0;
			clocks[0] = 1;
			clocks[1] = 0;
			clocks[2] = 0;
			clocks[3] = 0;
			
			while ( step_counter < cfg->args[0]  && verify_monopolyze(areas, cfg->args[0])){
				top_row = ( limits[0] + limits[1] ) / 2 - 1;
				down_row = ( limits[0] + limits[1] ) / 2;
				left_col = ( limits[2] + limits[3] ) / 2 - 1;
				right_col = ( limits[2] + limits[3] ) / 2;
				int i = 0;
				
				while ( i < 4 && clocks[i] == 1 ){
					i ++;
					
				};
				
				if ( i == 4 ){
					i = 0;
					clocks[0] = 1;
					clocks[1] = 0;
					clocks[2] = 0;
					clocks[3] = 0;
				}
				else
					clocks[i] = 1;
					
				switch ( i ){
					case 0:
						move_to_row(gr, limits[1], down_row, 1);
						break;
					
					case 1:
						move_to_column(gr, limits[3], right_col, 1);
						break;
						
					case 2:
						move_to_row(gr, limits[0], top_row, 1);
						break;
					
					case 3:
						move_to_column(gr, limits[2], left_col, 1);
						break;
				}
				step_counter++;
				retraction_from_grid(gr);
				area_rest = get_area(gr, limits );
				
				update_area_stats( &areas, area_rest );
			}
			
			
			break;
			
		case 3:
			/* It moves the nodes towards the center, moving row from top to center,
			 *   row from down to center, column from right to center, column from left to center */
		
			step_counter = 0;
			
			while ( step_counter < cfg->args[0] && verify_monopolyze(areas, cfg->args[0])){
				top_row = ( limits[0] + limits[1] ) / 2 -1;
				down_row = ( limits[0] + limits[1] ) / 2 ;
				left_col = ( limits[2] + limits[3] ) / 2 -1;
				right_col = ( limits[2] + limits[3] ) / 2 ;
				i = 0;
							
				while ( i < 4 && clocks[i] == 1 ){
					i ++;
				};
				
				if ( i == 4 ){
					i = 0;
					clocks[0] = 1;
					clocks[1] = 0;
					clocks[2] = 0;
					clocks[3] = 0;
				}
				else
					clocks[i] = 1;
					
				switch ( i ){
					case 0:
						move_to_row(gr, limits[1], down_row, 1);
						break;
					
					case 1:
						move_to_row(gr, limits[0], top_row, 1);
						break;
						
					case 2:
						move_to_column(gr, limits[3], right_col, 1);
						break;
					
					case 3:
						move_to_column(gr, limits[2], left_col, 1);
						break;
				}
				step_counter++;
				retraction_from_grid(gr);
				area_rest = get_area(gr, limits );
				update_area_stats( &areas, area_rest );
			}
			break;
			
		case 4:
			/* It pushes the nodes towards angle at south-east, moving rows towards row at the bottom, columns towards at the right*/
			col_ext = gr->dims[0] - 1;
			row_ext = gr->dims[1] - 1;
			rc = 0;
			area_rest = -1;

			step_counter = 0;
			while ( step_counter < cfg->args[0] && verify_monopolyze(areas, cfg->args[0]) ){

				if ( rc == 0 ){
					move_to_row(gr, 0, row_ext, 1);
					if ( row_ext == -1 ) row_ext = gr->dims[1];
					rc = 1;
				}
				else {
					move_to_column(gr, 0, col_ext, 1);
					if ( col_ext == -1 ) col_ext = gr->dims[0];
					rc = 0;
				}
				step_counter ++;
				retraction_from_grid(gr);
				area_rest = get_area(gr, limits );
				update_area_stats( &areas, area_rest );

			}
			break;	
			
		}
		
		int area_tot = get_area( gr, limits );

		double stop = (double)clock();
		double tr = (double)(stop - start);
		values->alghoritm = cfg->alghoritm;
		values->real_nodes_number = real_nodes_number(gr);
		values->start_area = area_before;
		values->final_area = area_tot;
		values->start_bends = bends_before;;
		values->final_bends = bends_number( gr );
		values->start_length = length_before;
		list_real_arcs* arcs2 = create_list_arcs(gr, -1);
		values->final_length = segments_length(arcs2 );
		free_list_real_arcs(arcs2);
		arcs2 = NULL;
		values->elapsed_time = tr;
		list_areas* temp_area;
		
		while (areas != NULL){
			temp_area = areas;
			areas = areas->next;
			free(temp_area);
			temp_area = NULL;
		}
};

void elaborate_each_grid(char* file_name, int lenstr, char* directory, char* directory_out, config* cfg, char* stats_file){
	/* Loads grid from file, elaborates it and updates stats  */
	
	char* file_name_load;
	char* file_name_save;
	file_name_load = malloc(sizeof(char)*lenstr);
		
	sprintf(file_name_load, "%s/%s", directory, file_name);/* Input grid filename*/

	stats* values = malloc( sizeof( stats ) );	/* Output stats creation */
	
	grid* gr = load_grid( file_name_load );	/* Loads a grid in directory*/
	start_grid = load_grid( file_name_load );
	current_cfg = cfg;
	
	elaborate_grid( gr, cfg, values);	/* Elaborates grid and returns modified values */
	current_grid = gr;
	
	
	printf("Alghoritm %i\n", cfg->alghoritm);
	printf("NomeFile %s\n", file_name);
	printf("Nome%s\n", file_name);
	
	if (!opengl)stats_update(stats_file, values );	/* Updates stats_file with modified values */
	
	mkdir( directory_out,  0777 );		/* Creates output directory*/

	file_name_save = malloc(sizeof(char)*lenstr);
	sprintf(file_name_save, "%s/%s", directory_out, file_name); /*	Output grid filename */

	save_grid( gr, file_name_save );	/* Saves grid file in output directory*/
	if (!opengl){
		free_grid(gr);
		gr = NULL;
	}
	free( values );
	values = NULL;
	free( file_name_load );
	file_name_load = NULL;
	free( file_name_save );
	file_name_save = NULL;
}

void elaborate_grids( char* directory, char* stats_file, config* cfg ){
	/* Elaborates all grids file in directory with cfg configuration and updates stats_file */
	char ** file_names;
	int grids_number = scan_grids( directory, &file_names );
	
	int i;
	int lenstr = 40;
	
	char* directory_out = malloc(sizeof(char)*lenstr);
	sprintf(directory_out, "%s_out",directory);
	
	char* config_file = malloc(sizeof(char)*lenstr);

	if ( cfg == NULL ){
		sprintf(config_file, "%s/config.conf", directory );
		cfg = load_config( config_file );
		
	}
	if (!opengl){
	
		for ( i = 0; i < grids_number; i++ ){
			elaborate_each_grid(file_names[i], lenstr, directory, directory_out, cfg, stats_file);
			
		}
	}
	else{
		i = 0;
		while (i < grid_to_display) 
			i++;
		if (i < grids_number)
			elaborate_each_grid(file_names[i], lenstr, directory, directory_out, cfg, stats_file);
	
	}

	/* Free memory operations */
	free( directory_out );
	directory_out = NULL;
	free( config_file );
	config_file = NULL;
	free(file_names);
	file_names = NULL;
};

int main(int argc,  char** argv){
	consider_free = 1;
	
	
	if ( argc < 3 ){
		printf("Use: ./grafi graphs_dir stats_file verify_labels [alghoritm [args]]\n");
	}
	else {
		
		char* graph_dir = argv[1];
		char* stats_file = argv[2];
		
		if (!strcmp(stats_file, "opengl")){
			opengl = 1;
			grid_to_display = atoi(argv[argc-1]);
		}
		else opengl = 0;
		verify = !atoi(argv[3]);
		
		int alghoritm;
		int use_config_files = 0;
		config* cfg = NULL;
		
		if ( argc >= 5 ){
			alghoritm = atoi( argv[4] );
			use_config_files  = 1;
			cfg = malloc( sizeof( config ) );
			cfg->args = calloc( argc - 5, sizeof(  int ) );
			cfg->alghoritm = alghoritm;
			
			int i;
			
			for ( i = 5; i < argc; i++ )
				cfg->args[i-5] = atoi( (char*)argv[i] );
				
		}
		printf("Stats file %s\n", stats_file);
		elaborate_grids( graph_dir, stats_file, cfg );

		if (opengl){
			init_gl(argc, argv, start_grid, current_grid, current_cfg);
		    
		}
		free(cfg->args);
		cfg->args = NULL;
		free(cfg);
		cfg = NULL;
	}    
	return 1;
}
